package com.logic.landseaserver.service.callback;

import java.util.List;
import java.util.Map;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.logic.landseaserver.common.LandeaConstants.DdingConstant;
import com.logic.landseaserver.common.LandseaErrorMessageEnum;
import com.logic.landseaserver.common.exception.LandseaException;
import com.logic.landseaserver.domain.AbstractCallbackEvt;
import com.logic.landseaserver.domain.DdingPwdCallbackEvt;
import com.logic.landseaserver.domain.DdingRoomSync;
import com.logic.landseaserver.persistence.read.DdingRoomSyncReadMapper;
import com.logic.landseaserver.persistence.write.DdingRoomSyncWriteMapper;
import com.logic.landseaserver.service.IDdLockService;

@Service(DdingConstant.CALLBACK_EVNET_SERVICE_NAME_PREFIX + "Password_Update_Service")
public class DdingUpdatePasswordEvtHandler implements IEventCallbackHandler
{
    private static final Logger LOG = LoggerFactory.getLogger(DdingUpdatePasswordEvtHandler.class);
    
    @Autowired
    private DdingRoomSyncReadMapper ddingRoomSyncReadMapper;
    
    @Autowired
    private DdingRoomSyncWriteMapper ddingRoomSyncWriteMapper;
    
    @Autowired
    private IDdLockService ddLockService;
    
    @SuppressWarnings("unchecked")
    @Override
    public Object process(AbstractCallbackEvt callbackEvent)
        throws LandseaException
    {
        try
        {
            DdingPwdCallbackEvt event = (DdingPwdCallbackEvt)callbackEvent;
            
            // 获取result
            Object resultObject = event.getResult();
            if (null == resultObject)
            {
                LOG.error("DdingUpdatePasswordEvtHandler|Error|result is empty.");
                throw LandseaException.createException(LandseaErrorMessageEnum.DDINGLOCK_CALLBACK_PARAM_ERROR);
            }
            
            Map<String,Object> resultMap = (Map<String,Object>)resultObject;
            
            // 先获取serviceId，如果不是本地的，则直接忽略
            String serviceId = event.getServiceid();
            if (StringUtils.isEmpty(serviceId))
            {
                LOG.info("DdingUpdatePasswordEvtHandler|serviceId为空，处理结束.");
                return null;
            }
            
            // 密码的Id
            Integer passwordId = (Integer)resultMap.get("id");
            // 修改密码的结果
            Integer errNo = (Integer)resultMap.get("ErrNo");
            
            if (null != passwordId)
            {
                if (999 == passwordId.intValue())
                {
                    // 如果是管理员密码，直接丢弃
                    LOG.info("DdingUpdatePasswordEvtHandler|密码ID为999的是管理员密码，消息忽略.");
                    return null;
                }
                
                // 更新到数据库
                processLocal(event, passwordId, errNo, serviceId);
            }
            
            return null;
        }
        catch (LandseaException e)
        {
            throw e;
        }
        catch (Exception e)
        {
            LOG.error("DdingUpdatePasswordEvtHandler|handle callback event failed.", e);
            throw LandseaException
                .createException(LandseaErrorMessageEnum.DDINGLOCK_CALLBACK_PROCESS_PASSWORD_ERROR, e);
        }
    }
    
    // 处理新增密码回调
    private void processLocal(DdingPwdCallbackEvt event, Integer passwordId, Integer errNo, String serviceId)
        throws LandseaException
    {
        // 门锁设备uuid
        String uuid = event.getUuid();
        
        if (StringUtils.isEmpty(uuid))
        {
            LOG.error("processLocal|Error|uuid is empty.");
            throw LandseaException.createException(LandseaErrorMessageEnum.DDINGLOCK_CALLBACK_PARAM_ERROR);
        }
        
        // 根据设备Id查询房间信息
        List<DdingRoomSync> ddingRoomSyncList = ddingRoomSyncReadMapper.selectByLockUuid(uuid);
        if (CollectionUtils.isEmpty(ddingRoomSyncList))
        {
            LOG.error("processLocal|Error|can not find room with lock uuid=" + uuid);
            throw LandseaException.createException(LandseaErrorMessageEnum.DDINGLOCK_CALLBACK_NOT_EXISTS_ROOM_ERROR);
        }
        // 门锁只能装在一间房内，所以只要取第一条记录即可
        DdingRoomSync ddingRoomSync = ddingRoomSyncList.get(0);
        
        if (!StringUtils.equals(serviceId, ddingRoomSync.getServiceId()))
        {
            LOG.error("processLocal|修改门锁密码回调|serviceId不匹配.请求ServiceId=" + serviceId + ",本地为" + ddingRoomSync.getServiceId());
            return;
        }
        
        try
        {
            // 更新数据库,只更新密码同步状态为成功
            DdingRoomSync updateRecord = new DdingRoomSync();
            updateRecord.setRoomId(ddingRoomSync.getRoomId());
            updateRecord.setPasswordId(passwordId);
            
            // 1000为成功，其他数字均为失败
            if (DdingConstant.CALLBACK_PASSWORD_EVENT_SUCCESS != errNo)
            {
                // 失败记录日志，更新数据库修改密码状态为修改失败
                LOG.error("DdingUpdatePasswordEvtHandler|Error|update password failed,resultCode is " + errNo);
                updateRecord.setPasswordState(DdingConstant.LOCK_PWD_SYNC_STATE_FAILED);
            }
            else
            {
                updateRecord.setPasswordState(DdingConstant.LOCK_PWD_SYNC_STATE_FINISH);
            }
            
            ddingRoomSyncWriteMapper.updateByPrimaryKeySelective(updateRecord);
            
            // 判断是否需要发短信
            if (ddingRoomSync.getNeedSendSms())
            {
                // 给用户发送短信，告知其密码明文，此处在以上事务内，发短信本身为异步，只要发送动作完成即认为发送成功，提交事务
                ddLockService.sendPwdMsgToUser(ddingRoomSync);
            }
        }
        catch (Exception e)
        {
            LOG.error("processLocal|Error|update lock password info to database failed,roomId=" + ddingRoomSync.getRoomId(), e);
            throw LandseaException.createException(LandseaErrorMessageEnum.DDINGLOCK_UPDATE_ROOM_LOCK_PASSWORD_ERROR, e);
        }
    }
}
